using DA.AnimGraph;
using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {

    internal class InspectorField_TimelinePerk : InspectorField<AGAPerkModel_Timeline> {

        private Timeline timeline;
        private ListViewAGE eventListView;
        private GenericMenu addEventMenu;
        private Dictionary<string, Type> typesDict;

        protected override void BuildUI() {
            labelText = "Timeline";

            typesDict = TimelineEventTypeRegister.GetInstance().GetTimelineEventTypes();
            if (typesDict == null) {
                return;
            }

            timeline = ageContext.timelineManager.GetTimelineOrAddDefault(source.timelineUuid);

            addEventMenu = new GenericMenu();
            foreach (var type in typesDict) {
                addEventMenu.AddItem(new GUIContent(type.Key), false, () => AddEvent(type.Value));
            }

            BuildListView2();
        }
        void BuildListView2() {
            eventListView = new ListViewAGE() {
                title = $"{source.timelineUuid}",
                enableCountController = true,
                itemsSource = timeline.events,
            };
            eventListView.makeItem = () => {
                var w = new FoldoutWrapper();
                w.upButtonClicked += (index) => {
                    (timeline.events[index], timeline.events[index - 1]) = (timeline.events[index - 1], timeline.events[index]);

                    eventListView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.downButtonClicked += (index) => {
                    (timeline.events[index], timeline.events[index + 1]) = (timeline.events[index + 1], timeline.events[index]);

                    eventListView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                w.deleteButtonClicked += (index) => {
                    timeline.events.RemoveAt(index);
                    eventListView.Rebuild();
                    inspectorChangeCallback?.Invoke();
                };
                var l = new InspectorField_TimelineEvent();
                return (l, w);
            };

            eventListView.bindItem = (element, wrapper, index) => {
                if (element is InspectorField_TimelineEvent field) {
                    field.Init(null, timeline.events[index], ageContext, inspectorChangeCallback);
                }
                if (wrapper is FoldoutWrapper w) {
                    w.index = index;
                    w.text = $"[{index}] {timeline.events[index].parameter.GetType().Name}";
                    w.enableUp = index > 0;
                    w.enableDown = index < timeline.events.Count - 1;
                    w.enableDelete = true;
                }
            };

            eventListView.addButtonClicked = () => {
                var menuPos = eventListView.LocalToWorld(new Vector2(0, 5));
                addEventMenu.DropDown(new Rect(menuPos, Vector2.zero));
            };
        }

        protected override void DrawUI() {
            if (typesDict == null) {
                Add(new Label("cant find any Timeline Event"));
                return;
            }
            Add(eventListView);
        }

        protected override void ClearUI() {
            Clear();
        }

        /// 实例化事件对象
        void AddEvent(Type eventType) {
            var parameterInstance = Activator.CreateInstance(eventType) as TimelineEventParameter;
            D.A(parameterInstance != null, "添加timeline event 失败，类型错误");
            var newEvt = new TimelineEvent() {
                uuid = AUIDGenerator.Gen(),
                time = 0,
                endTime = 0,
                parameter = parameterInstance,
            };
            timeline.events.Add(newEvt);
            eventListView.Rebuild();
            inspectorChangeCallback?.Invoke();
        }
    }

    internal class InspectorField_TimelineEvent : InspectorField<TimelineEvent> {

        FloatField timeField;
        FloatField endTimeField;
        Toggle triggerBeforeEndField;
        VisualElement container;

        public InspectorField_TimelineEvent() {
        }

        protected override void BuildUI() {
            var state = source.parameter.state;
            if (state != TimelineEventState.Always) {
                timeField = new FloatField("time");
                timeField.value = source.time;
                timeField.RegisterValueChangedCallback(evt => OnChanged());
            }

            if (state == TimelineEventState.HoldStart) {
                endTimeField = new FloatField("end time");
                endTimeField.value = source.endTime;
                endTimeField.RegisterValueChangedCallback(evt => OnChanged());
            }

            if (state == TimelineEventState.Trigger) {
                triggerBeforeEndField = new Toggle("确保触发");
                triggerBeforeEndField.value = (source.flag & TimelineEventFlag.TriggerBeforeExit) != TimelineEventFlag.None;
                triggerBeforeEndField.RegisterValueChangedCallback(evt => OnChanged());
            }

            container = new VisualElement();
        }

        protected override void DrawUI() {
            if (timeField != null) {
                Add(timeField);
            }
            if (endTimeField != null) {
                Add(endTimeField);
            }
            if (triggerBeforeEndField != null) {
                Add(triggerBeforeEndField);
            }
            Add(container);
            BuildByType(source.parameter);
        }

        void BuildByType(TimelineEventParameter eventObject) {
            var type = eventObject.GetType();
            var fields = type.GetFields();
            foreach (var field in fields) {
                var eventParameter = Attribute.GetCustomAttribute(field, typeof(EventParameterAttribute));
                if (eventParameter == null) continue;

                var insField = InspectorFieldFactory.SwitchField(field.FieldType);
                if (insField != null) {
                    insField.Init(field.Name, field.GetValue(eventObject), ageContext, null);
                    container.Add(insField);
                }
            }

        }

        private void OnChanged() {
            if (timeField != null) {
                source.time = timeField.value;
            }
            if (endTimeField != null) {
                source.endTime = endTimeField.value;
                D.A(source.endTime > source.time, "范围事件的结束时间必须晚于开始时间");
            }
            if (triggerBeforeEndField != null) {
                source.flag = triggerBeforeEndField.value ? source.flag | TimelineEventFlag.TriggerBeforeExit : source.flag & ~TimelineEventFlag.TriggerBeforeExit;
            }
            inspectorChangeCallback?.Invoke();
        }

    }
}
